﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.Pathing;
using Styx.Plugins;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace DruidUnstuckerFlight
{
    public class Plugin : HBPlugin
    {
        private readonly Stopwatch _unstuckTimer = new Stopwatch();
        private readonly Stopwatch _blackscreenTimer = new Stopwatch();
        private WoWPoint _stuckpoint, _twentyFeetAboveMe, _blackscreenPoint;
        private static readonly LocalPlayer Me = StyxWoW.Me;
        private bool _initalized;
        public static string GlobalSettingsFile { get { return Path.Combine(SettingsFolder, "DruidFlightAntiStuck[" + Me.Name +"-"+Me.RealmName+ "].cfg"); } }
        
        public static Form1 Window;

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(Window = new Form1());
        }
        
        public static string HbFolder
        {
            get { return Path.GetDirectoryName(Application.ExecutablePath); }
        }

        public static string SettingsFolder
        {
            get { return Path.Combine(HbFolder, "Settings"); }
        }

        public static string DataFolder
        {
            get { return Path.Combine(HbFolder, "Data"); }
        }
        public static string PluginFolder
        {
            get { return Path.Combine(HbFolder, "Plugins"); }
        }
        public static string ThisPluginPath
        {
            get { return Path.Combine(PluginFolder, "Druid Flight Unstucker"); }
        }

        public override void OnButtonPress()
        {
            Window = new Form1();
            Window.Show();
        }

        public override bool WantButton
        {
            get { return true; }
        }

        public override void Dispose()
        {
            ObjectXMLSerializer<Settings>.Save(Settings.Instance, GlobalSettingsFile);
            BotEvents.OnBotStarted -= BotEvent_OnBotStarted;
            BotEvents.OnBotStopped -= BotEvent_OnBotStopped;
        }
        public void BotEvent_OnBotStarted(EventArgs args)
        {
            ObjectXMLSerializer<Settings>.Save(Settings.Instance, GlobalSettingsFile);
        }
        public void BotEvent_OnBotStopped(EventArgs args)
        {
            ObjectXMLSerializer<Settings>.Save(Settings.Instance, GlobalSettingsFile);
        }
        public override void Initialize()
        {
            try
            {
                Settings.Instance = ObjectXMLSerializer<Settings>.Load(GlobalSettingsFile);
            }
            catch (Exception)
            {
                Settings.Instance = new Settings();
            }
            _initalized = true;
            _stuckpoint = Me.Location;
            _blackscreenPoint = Me.Location;
            BotEvents.OnBotStarted += BotEvent_OnBotStarted;
            BotEvents.OnBotStopped += BotEvent_OnBotStopped;
        }

        
        public override void Pulse()
        {
            if (Me.Class != WoWClass.Druid || Me.IsDead || Me.Combat)
            {
                _unstuckTimer.Reset();
                return;
            }
            if (Settings.Instance.DetectBlackscreen)
            {
                BlackScreenCheck();
            }
            if(!_unstuckTimer.IsRunning)
                _unstuckTimer.Start();
            FallingCheck();
            FlyUpCheck();
            CancelFlightFormCheck();
        }

        private void FallingCheck()
        {
            if (!Me.IsFalling || Me.HasAura(40122)) return;
            Logging.Write("I'm falling - Casting Swift Flight Form");
            Thread.Sleep(500);
            SpellManager.Cast("Swift Flight Form");
        }

        private void CancelFlightFormCheck()
        {
            if (_unstuckTimer.ElapsedMilliseconds <= (Settings.Instance.CancelFlightFormSeconds*1000)) return;
            if (_stuckpoint.Distance(Me.Location) < Settings.Instance.AntiStuckDistanceYards && Me.HasAura(40122) && !Me.Combat)
            {
                Logging.Write("Cancelling flight form due to being stuck within " + Settings.Instance.AntiStuckDistanceYards + " yards for more than " + Settings.Instance.CancelFlightFormSeconds + " seconds");
                SpellManager.Cast("Swift Flight Form");
                Thread.Sleep(400);
                if (Settings.Instance.CancelFlightFormSeconds < Settings.Instance.FlyUpSeconds)
                    return;
            }
            _stuckpoint = Me.Location;
            _unstuckTimer.Restart();
        }

        private void FlyUpCheck()
        {
            if (_unstuckTimer.ElapsedMilliseconds <= (Settings.Instance.FlyUpSeconds*1000)) return;
            if (_stuckpoint.Distance(Me.Location) < Settings.Instance.AntiStuckDistanceYards && Me.HasAura(40122))
            {
                _twentyFeetAboveMe = new WoWPoint(Me.Location.X, Me.Location.Y,
                                                  (Me.Location.Z + Settings.Instance.AntiStuckHeight));
                Logging.Write("Flying " + Settings.Instance.AntiStuckHeight +
                              (Settings.Instance.AntiStuckHeight > 0
                                   ? " yards up in the air."
                                   : " yards down to unstuck."));
                while (_twentyFeetAboveMe.Distance(Me.Location) > 5)
                {
                    Flightor.MoveTo(_twentyFeetAboveMe);
                }
                if (Settings.Instance.CancelFlightFormSeconds > Settings.Instance.FlyUpSeconds)
                    return;
            }
            _stuckpoint = Me.Location;
            _unstuckTimer.Restart();
        }

        private void BlackScreenCheck()
        {
            if (!_blackscreenTimer.IsRunning)
                _blackscreenTimer.Start();
            if (_blackscreenTimer.ElapsedMilliseconds <= (Settings.Instance.ReloadUITimer*1000)) return;
            if (_blackscreenPoint.Distance(Me.Location) < 2)
            {
                Lua.DoString("ReloadUI()");
            }
            _blackscreenTimer.Restart();
            _blackscreenPoint = Me.Location;
        }
        public override string Name
        {
            get { return "Druid Unstucker Flight"; }
        }

        public override string Author
        {
            get { return "Stove"; }
        }

        public override Version Version
        {
            get { return new Version(1, 0); }
        }
    }
}
